package bat.iog.hytool.Host;


import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class HostsDemo implements Runnable  {

    public static String LOCALIP = "172.16.200.194";
    public static int POST = 8002;
    public static int THREAD_NUM = 500;
    private static final String HexStr = "0123456789ABCDEF";
    private static final char HexCharArr[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    private static final String heartHexString = "000000D800000000";
    private static List<InetAddress> localIPList = new ArrayList<InetAddress>();
    SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static FileWriter fwlog = null;
    public static File log = new File("/logC.txt");
    public Map<String,Integer> sentNum=new ConcurrentHashMap<String,Integer>();
    public Socket socket = null;
    public boolean isConnection = false;

    public static void main(String[] args) {
        localIPList = getLocalIPList();
        HostsDemo Hosts = new HostsDemo();
        Hosts.jpanel();
    }

    @Override
    public void run() {
        init();
    }

    public void init(){
        InetAddress localAddr = localIPList.get(Integer.parseInt(Thread.currentThread().getName().substring(4)));
        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        int localPort = 9000 + Integer.parseInt(Thread.currentThread().getName().substring(4));
        boolean initsocket = true;
        int lognums = 0;
        while (initsocket) {
            initsocket = false;
            try {
                socket = new Socket();
                SocketAddress localAddress = new InetSocketAddress(localAddr,localPort+1);
                SocketAddress serverAddress = new InetSocketAddress(LOCALIP,POST);
                socket.setKeepAlive(true);
                socket.bind(localAddress);
                socket.connect(serverAddress);
                isConnection = true;

                //打印日志
                String logs = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "创建连接！";
                printLogs(logs);

                Thread sender = new Thread(new Sender(),"send"+Thread.currentThread().getName());
                sender.start();

                Thread receive = new Thread(new Receiver(),"rece"+Thread.currentThread().getName());
                receive.start();
            } catch (IOException e) {
                //打印日志
                String logs =dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "创建连接异常！";
                if (lognums < 1) {
                    printLogs(logs + ": " +e);
                    lognums++;
                }
                initsocket = true;
                printLogs(logs + ": " +e);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
            }
        }
    }

    /**
     * 发送心跳报文
     */
    class Sender implements Runnable {
        @Override
        public void run() {
            OutputStream out = null;
            boolean isSenderRunning = true;
            InetAddress localAddr = localIPList.get(Integer.parseInt(Thread.currentThread().getName().substring(8)));
            sentNum.put(localAddr.toString(),0);
            
            int repeatConnectCount = 0;
            boolean isBankaSendered = true;
            while (isSenderRunning){

                if (isConnection) {
                    //发送心跳
                    try {

                        int SENT_NUM = sentNum.get(localAddr.toString())+1;
                        sentNum.put(localAddr.toString(),SENT_NUM);

                        //initheart = false;
                        //发送心跳
                        byte[] bytes = hexStr2Str(heartHexString);
                        out = socket.getOutputStream();
                        //hearstartime = new Date().getTime();
                        out.write(bytes);
                        out.flush();

                        //打印日志
                        String sendlogs = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "发送心跳：";
                        //printLogs(sendlogs);
                        //System.out.println("发送心跳");

                    } catch (SocketException e) {
                        isConnection = false;
                        String sendlogs = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "发送心跳时，连接中断！";
                        printLogs(sendlogs + ": "+ e);
                    } catch (IOException e) {
                        //打印日志
                        String sendlogs = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "发送心跳异常！";
                        printLogs(sendlogs + ": "+ e);
                        e.printStackTrace();
                    }
                    
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                    //发送板卡信息
                    if(isBankaSendered){
                        isBankaSendered = false;
                        try {
                            out = socket.getOutputStream();
                            //发送板卡信息
                            byte[] bankaBytes = hexStr2Str("000000B00000000C0A010901010106FBACA1A100");
                            //bankstartime = new Date().getTime();
                            out.write(bankaBytes);
                            out.flush();

                            //打印日志
                            String bankalogs = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "发送板卡信息！";
                            //printLogs(bankalogs);

                        } catch (SocketException e) {
                            isConnection = false;
                            System.out.println("发送板卡信息时，连接中断！");
                            String bankalogs = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "发送板卡信息时，连接中断！";
                            printLogs(bankalogs + ": "+ e);
                        } catch (IOException e) {
                            String bankalogs = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "发送板卡信息异常！";
                            printLogs(bankalogs + ": "+ e);
                        }

                        try {
                            Thread.sleep(10000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }

                //发送三次没有接收到报文，重新连接
                if (sentNum.get(localAddr.toString()) > 2 || !isConnection) {

                    socket = new Socket();
                    SocketAddress serverAddress = new InetSocketAddress(LOCALIP,POST);
                    SocketAddress localAddress = new InetSocketAddress(localAddr,getLocalPost()+1);
                    try {
                        socket.setKeepAlive(true);
                        socket.bind(localAddress);
                        socket.connect(serverAddress);
                        //重连成功
                        sentNum.put(localAddr.toString(),0);
                        repeatConnectCount = 0;

                        //打印日志
                        String reconLog = "";
                        if (!isConnection) {
                            reconLog  = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "重新连接成功！";
                        } else {
                            reconLog = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "发送三次心跳没有接收到报文，重新连接成功！";
                        }
                        printLogs(reconLog);
                        isConnection = true;
                    } catch (IOException e) {
                        if (repeatConnectCount < 1){
                            //打印日志
                            String sendlogs = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "重新创建连接异常！继续重连";
                            printLogs(sendlogs + ": "+ e);
                            repeatConnectCount++;
                        }
                        try {
                            Thread.sleep(10000);
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    /**
     * 接收报文
     */
    class Receiver implements Runnable {
        public InputStream in = null;
        @Override
        public void run() {
            boolean isreceiverRunning = true;
            InetAddress localAddr = localIPList.get(Integer.parseInt(Thread.currentThread().getName().substring(8)));
            while (isreceiverRunning){

                if (isConnection) {
                    try {
                        //fwlog = new FileWriter(log,true);
                        in = socket.getInputStream();
                        //接收心跳
                        byte[]  receivebuf = new byte[10];
                        while ((in.read(receivebuf)) != -1) {
                            //打印日志
                            String receivelogs = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "接收报文：" + byteArrToHex(receivebuf);
                            printLogs(receivelogs);
                            sentNum.put(localAddr.toString(),0);
                            String receiveBytes = byteArrToHex(receivebuf).substring(0,16);
                            //板卡信息
                            if (receiveBytes.equals("000000B000000000")) {
                                OutputStream out =null;
                                out = socket.getOutputStream();
                                //发送板卡信息
                                byte[] bankaBytes = hexStr2Str("000000B00000000C0A010901010106FBACA1A100");
                                out.write(bankaBytes);
                                out.flush();

                                //打印日志
                                String log = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "通过接收到的报文，向服务器发送板卡信息！";
                                //printLogs(log);
                            //绝缘测试
                            } else if (receiveBytes.equals("000000A000000002")){
                                
                                OutputStream out =null;
                                out = socket.getOutputStream();
                                //绝缘测试确认报文
                                byte[] confirmBytes = hexStr2Str("000000A000000000");
                                out.write(confirmBytes);
                                out.flush();
                                
                                //绝缘测试应答报文
                                String header = "000000A0";
                                String datasize = "00000007";
                                String request = byteArrToHex(receivebuf);
                                String solt = request.substring(16,18);
                                if ("FF".equals(solt)){
                                    solt = "0A";
                                }
                                String direction = request.substring(18,20);
                                String sourse = "00";
                                String revent = "7f800000";
                                byte[] responseBytes = hexStr2Str(header+datasize+solt+direction+sourse+revent);
                                out = socket.getOutputStream();
                                out.write(responseBytes);
                                out.flush();
                                
                                //打印日志
                                String log = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "通过接收到的报文，向服务器发送绝缘测试信息";
                                printLogs(log + ": "+ header+datasize+solt+direction+sourse+revent);
                            //接地测试
                            } else if (receiveBytes.equals("0000000A00000001")){
                                OutputStream out =null;
                                out = socket.getOutputStream();
                                //接地测试确认报文
                                byte[] confirmBytes = hexStr2Str("0000000A00000000");
                                out.write(confirmBytes);
                                out.flush();
                                
                                //接地测试应答报文
                                String header = "0000000A";
                                String datasize = "00000006";
                                String solt = "0A";
                                String sourse = "00";
                                String revent = "7f800000";
                                byte[] responseBytes = hexStr2Str(header+datasize+solt+sourse+revent);
                                out = socket.getOutputStream();
                                out.write(responseBytes);
                                out.flush();
                                
                                //打印日志
                                String log = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "通过接收到的报文，向服务器发送接地信息";
                                printLogs(log + ": "+header+datasize+solt+sourse+revent) ;
                            }
                        }
                    }catch (SocketException e) {
                        //打印日志
                        String receivelogs = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "接收数据时，连接中断！";
                        printLogs(receivelogs +": " +e);
                        isConnection =false;
                    }  catch (IOException e) {
                        //打印日志
                        String receivelogs = dateFormat.format(new Date().getTime())+" : "+localAddr.toString() + "接受心跳异常！";
                        printLogs(receivelogs +": " +e);
                        isConnection =false;
                    }
                }
                
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
            }
        }
    }

    /**
     * 画页面
     */
    public void jpanel(){
        // 创建 JFrame 实例
        JFrame frame = new JFrame("TEST");
        // Setting the width and height of frame
        frame.setSize(350, 250);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //创建面板，这个类似于 HTML 的 div 标签
        JPanel panel = new JPanel();
        // 添加面板
        frame.add(panel);
        //调用用户定义的方法并添加组件到面板
        placeComponents(panel);
        // 设置界面可见
        frame.setVisible(true);
    }

    /**
     * 画組件页面
     * @param panel
     */
    private static void placeComponents(JPanel panel) {
        //这边设置布局为 null
        panel.setLayout(null);
        // 创建 JLabel
        JLabel IPLabel = new JLabel("网管IP地址:");
        IPLabel.setBounds(10,20,80,25);
        panel.add(IPLabel);
        JTextField IPText = new JTextField(20);
        IPText.setBounds(100,20,165,25);
        IPText.setText(LOCALIP);
        panel.add(IPText);

        JLabel PortLabel = new JLabel("网管端口号:");
        PortLabel.setBounds(10,50,80,25);
        panel.add(PortLabel);
        JTextField PortText = new JTextField(20);
        PortText.setBounds(100,50,165,25);
        PortText.setText(String.valueOf(POST));
        panel.add(PortText);

        JLabel ThreadNumLabel = new JLabel("主机数:");
        ThreadNumLabel.setBounds(10,80,80,25);
        panel.add(ThreadNumLabel);
        JTextField ThreadNumText = new JTextField(20);
        ThreadNumText.setBounds(100,80,165,25);
        ThreadNumText.setText(String.valueOf(localIPList.size() < THREAD_NUM ? localIPList.size() : THREAD_NUM));
        panel.add(ThreadNumText);

        // 创建登录按钮
        final JButton loginButton = new JButton("开始测试");
        loginButton.setBounds(10, 110, 80, 25);
        panel.add(loginButton);

        IPText.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                LOCALIP = IPText.getText().trim()== null ? "" : IPText.getText().trim();
            }
        });

        PortText.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                POST = Integer.parseInt(PortText.getText().trim() == null ? "8002" : PortText.getText().trim());
            }
        });
        THREAD_NUM = localIPList.size() < THREAD_NUM ? localIPList.size() : THREAD_NUM;
        ThreadNumText.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                THREAD_NUM =  Integer.parseInt(ThreadNumText.getText().trim() == null ? "1" : ThreadNumText.getText().trim());
                THREAD_NUM = localIPList.size() < THREAD_NUM ? localIPList.size() : THREAD_NUM;
            }
        });

        loginButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                loginButton.setEnabled(false);
                for (int i = 0; i < THREAD_NUM; i++) {
                    Thread thread = new Thread(new HostsDemo(), "host" + i );
                    thread.start();
                }
            }
        });
    }


    /**
     * 获取本地可用端口
     * @return
     */
    public int getLocalPost(){
        ServerSocket serverSocket = null; //读取空闲的可用端口
        try {
            serverSocket = new ServerSocket(0);
        } catch (IOException e) {
            e.printStackTrace();
            return 9999;
        }
        return serverSocket.getLocalPort();
    }

    /**
     * 获取可用IP
     * @return
     */
    public static List<InetAddress> getLocalIPList() {
        List<InetAddress> ip4List = new ArrayList<InetAddress>();
        try {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            NetworkInterface networkInterface;
            Enumeration<InetAddress> inetAddresses;
            InetAddress inetAddress;
            while (networkInterfaces.hasMoreElements()) {
                networkInterface = networkInterfaces.nextElement();
                inetAddresses = networkInterface.getInetAddresses();

                while (inetAddresses.hasMoreElements()) {
                    inetAddress = inetAddresses.nextElement();
                    if (inetAddress != null
                            && !"127.0.0.1".equals(inetAddress.getHostAddress())
                            //&& "192".equals(inetAddress.toString().substring(1,4))
                            //&& "192.168".equals(inetAddress.toString().substring(1,8))
//                            && ("192.168.126".equals(inetAddress.toString().substring(1,12)) 
//                            || "192.168.127".equals(inetAddress.toString().substring(1,12)) 
//                            || "172.16.200.235".equals(inetAddress.getHostAddress())
//                            || "172.16.200.223".equals(inetAddress.getHostAddress()))
                            && inetAddress instanceof Inet4Address) { // IPV4

                        ip4List.add(inetAddress);
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return ip4List;
    }

    /**
     * 十六进制字符串转换成 byte[]
     */
    public static byte[] hexStr2Str(String hexStr) {
        hexStr = hexStr.toString().trim().replace(" ", "").toUpperCase(Locale.US);
        char[] hexs = hexStr.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        int iTmp = 0x00;

        for (int i = 0; i < bytes.length; i++) {
            iTmp = HexStr.indexOf(hexs[2 * i]) << 4;
            iTmp |= HexStr.indexOf(hexs[2 * i + 1]);
            bytes[i] = (byte) (iTmp & 0xFF);
        }
        return bytes;
        // return new String(bytes);
    }
    /**
     * 将byte[]转换为十六进制字符串
     */
    public static String byteArrToHex(byte[] btArr) {
        char strArr[] = new char[btArr.length * 2];
        int i = 0;
        for (byte bt : btArr) {
            strArr[i++] = HexCharArr[bt >>> 4 & 0xf];
            strArr[i++] = HexCharArr[bt & 0xf];
        }
        return new String(strArr);
    }

    /**
     * 获取板卡数据
     * @return
     */
    public static final String getBanka(){

        String header = "000000B0";
        String datasize = "0000000C";
        String slot = "0A";
        String type = "01";
        String year = "09";//2011
        String mouth = "01";
        String day = "01";
        String squence = "0106FBAC";
        String hard ="A1";
        String soft = "A1";
        String stats = "00";
        String bankaHexString = header+datasize+slot+type+year+mouth+day+squence+hard+soft+stats;
        bankaHexString = "000000B00000000C0A010901010106FBACA1A100";
        return bankaHexString;
    }

    /**
     * 打印日志
     */
    public static synchronized void printLogs(String msg){
        try {
            System.out.println(msg);
            if (log.length()>1024000*50) {
                log.delete();
                fwlog = new FileWriter(log, true);
            } else {
                fwlog = new FileWriter(log, true);
            }
            fwlog.write(msg +"\n");
            fwlog.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if (fwlog != null) {
                try {
                    fwlog.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

